package com.gitee.smalllog.logback.appender.write;

import com.alibaba.fastjson.JSON;
import com.gitee.smalllog.core.MessageAppenderFactory;
import com.gitee.smalllog.core.client.RedisClient;
import com.gitee.smalllog.core.constant.LogMessageConstant;
import com.gitee.smalllog.core.model.BaseLogMessage;
import com.gitee.smalllog.core.model.RunLogMessage;
import com.gitee.smalllog.core.model.Settings;
import com.gitee.smalllog.core.utils.*;
import com.gitee.smalllog.core.write.SafeWriter;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicBoolean;

public class SmallLogWriter implements SafeWriter {
	private StringBuilder sendBuffer;
	private ErrorReporter errorReporter;
	private Settings settings;
	private RedisClient redisClient;
	private static final AtomicBoolean INIT = new AtomicBoolean();

	private boolean bufferExceeded;

	private static final ThreadPoolExecutor threadPoolExecutor
			= ThreadPoolUtil.getPool();

	public SmallLogWriter(ErrorReporter errorReporter, Settings settings) {
		this.errorReporter = errorReporter;
		this.settings = settings;
		this.sendBuffer = new StringBuilder();
	}

	/**
	 * 将结果写入到 sendBuffer
	 * @param cbuf
	 * @param off
	 * @param len
	 */
	@Override
	public void write(char[] cbuf, int off, int len) {
		/**
		 * 是否拒绝写入
		 */
		if (bufferExceeded) {
			return;
		}

		sendBuffer.append(cbuf, off, len);

		/**
		 * 如果超过队列大小直接拒绝
		 */
		if (sendBuffer.length() >= settings.getMaxQueueSize()) {
			errorReporter.logWarning("Send queue maximum size exceeded - log messages will be lost until the buffer is cleared");
			bufferExceeded = true;
		}
	}

	/**
	 * 发送数据到es服务端
	 * @throws IOException
	 */
	public void sendData() throws IOException {
		if (sendBuffer.length() <= 0) {
			return;
		}

		if (this.redisClient == null) {
			MessageAppenderFactory.initQueue(settings.getMaxQueueSize());
			this.redisClient = RedisClient
					.getInstance(settings.getRedisHost(), settings.getRedisPort(), settings.getRedisAuth(), 0);

			// 当多并发情况下若redisClient为空时会多次执行以下代码，因此增加是否已初始化的判断
			if (INIT.compareAndSet(false, true)) {
				for (int a = 0; a < settings.getThreadPoolSize(); a++) {

					threadPoolExecutor.execute(() -> {
						MessageAppenderFactory.startRunLog(this.redisClient, settings.getMaxQueueSize(),
								settings.isCompressor() ? LogMessageConstant.LOG_KEY_COMPRESS : LogMessageConstant.LOG_KEY,
								settings.isCompressor());
					});
//					threadPoolExecutor.execute(() -> {
//						MessageAppenderFactory.startTraceLog(this.redisClient, settings.getMaxQueueSize(),
//								settings.isCompressor()  ? LogMessageConstant.LOG_KEY_TRACE_COMPRESS : LogMessageConstant.LOG_KEY_TRACE, settings.isCompressor());
//					});
				}
			}
		}
		final BaseLogMessage logMessage = LogMessageThreadLocal.runLogMessage.get();
		if (logMessage instanceof RunLogMessage) {
			RunLogMessage runLogMessage = (RunLogMessage) logMessage;
			runLogMessage.setContent(sendBuffer.toString());
			final String message = LogMessageUtil.getLogMessage(runLogMessage);
			System.out.println("数据发送成功：" + message);
			MessageAppenderFactory.pushRundataQueue(message);
		} else {
			MessageAppenderFactory.pushTracedataQueue(GfJsonUtil.toJSONString(logMessage));
		}

		//final BaseLogMessage logMessage = LogMessageUtil.getLogMessage(settings.getAppName() , settings.getEvn(), loggingEvent);


		//清空
		sendBuffer.setLength(0);
		if (bufferExceeded) {
			errorReporter.logInfo("Send queue cleared - log messages will no longer be lost");
			bufferExceeded = false;
		}
	}

	public boolean hasPendingData() {
		return sendBuffer.length() != 0;
	}

	private static String slurpErrors(HttpURLConnection urlConnection) {
		try {
			InputStream stream = urlConnection.getErrorStream();
			if (stream == null) {
				return "<no data>";
			}

			StringBuilder builder = new StringBuilder();
			InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
			char[] buf = new char[2048];
			int numRead;
			while ((numRead = reader.read(buf)) > 0) {
				builder.append(buf, 0, numRead);
			}
			return builder.toString();
		} catch (Exception e) {
			return "<error retrieving data: " + e.getMessage() + ">";
		}
	}

}
